package com.piece.module.file.util.convert;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.converters.bigdecimal.BigDecimalBooleanConverter;
import com.alibaba.excel.converters.bigdecimal.BigDecimalNumberConverter;
import com.alibaba.excel.converters.bigdecimal.BigDecimalStringConverter;
import com.alibaba.excel.converters.biginteger.BigIntegerBooleanConverter;
import com.alibaba.excel.converters.biginteger.BigIntegerNumberConverter;
import com.alibaba.excel.converters.biginteger.BigIntegerStringConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanBooleanConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanNumberConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanStringConverter;
import com.alibaba.excel.converters.bytearray.BoxingByteArrayImageConverter;
import com.alibaba.excel.converters.bytearray.ByteArrayImageConverter;
import com.alibaba.excel.converters.byteconverter.ByteBooleanConverter;
import com.alibaba.excel.converters.byteconverter.ByteNumberConverter;
import com.alibaba.excel.converters.byteconverter.ByteStringConverter;
import com.alibaba.excel.converters.date.DateDateConverter;
import com.alibaba.excel.converters.date.DateNumberConverter;
import com.alibaba.excel.converters.date.DateStringConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleBooleanConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleNumberConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleStringConverter;
import com.alibaba.excel.converters.file.FileImageConverter;
import com.alibaba.excel.converters.floatconverter.FloatBooleanConverter;
import com.alibaba.excel.converters.floatconverter.FloatNumberConverter;
import com.alibaba.excel.converters.floatconverter.FloatStringConverter;
import com.alibaba.excel.converters.inputstream.InputStreamImageConverter;
import com.alibaba.excel.converters.integer.IntegerBooleanConverter;
import com.alibaba.excel.converters.integer.IntegerNumberConverter;
import com.alibaba.excel.converters.integer.IntegerStringConverter;
import com.alibaba.excel.converters.localdate.LocalDateNumberConverter;
import com.alibaba.excel.converters.localdatetime.LocalDateTimeDateConverter;
import com.alibaba.excel.converters.localdatetime.LocalDateTimeStringConverter;
import com.alibaba.excel.converters.longconverter.LongBooleanConverter;
import com.alibaba.excel.converters.longconverter.LongNumberConverter;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.converters.shortconverter.ShortBooleanConverter;
import com.alibaba.excel.converters.shortconverter.ShortNumberConverter;
import com.alibaba.excel.converters.shortconverter.ShortStringConverter;
import com.alibaba.excel.converters.string.StringBooleanConverter;
import com.alibaba.excel.converters.string.StringErrorConverter;
import com.alibaba.excel.converters.string.StringNumberConverter;
import com.alibaba.excel.converters.string.StringStringConverter;
import com.alibaba.excel.converters.url.UrlImageConverter;
import com.alibaba.excel.util.MapUtils;
import org.springframework.context.annotation.Bean;
import java.lang.reflect.Field;
import java.util.Map;

//@Configuration
public class ExcelConvertLoader {

    private static final String ALL_CONVERTER = "allConverter";

    private static final String WRITE_CONVERTER = "defaultWriteConverter";

    @Bean
    public DefaultConverterLoader init() throws Exception {
        DefaultConverterLoader loader = new DefaultConverterLoader();
        Field[] fields = loader.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.getType() == Map.class) {
                Map<ConverterKeyBuild.ConverterKey, Converter> convertMap = (Map<ConverterKeyBuild.ConverterKey, Converter>) field.get(loader);
                if (null != convertMap && !convertMap.isEmpty()) {
                    if (ALL_CONVERTER.equalsIgnoreCase(field.getName())) {
                        putAllConverter(convertMap, new CustomStringConverter());
                    } else if (WRITE_CONVERTER.equalsIgnoreCase(field.getName())) {
                        putAllConverter(convertMap, new CustomStringConverter());
                    }
                    field.set(loader, convertMap);
                } else {
                    if (ALL_CONVERTER.equalsIgnoreCase(field.getName())) {
                        initAllConverter(loader, field);
                    } else if (WRITE_CONVERTER.equalsIgnoreCase(field.getName())) {
                        initWriteConverter(loader, field);
                    }
                }
            }
        }

        return loader;
    }

    private void initAllConverter(DefaultConverterLoader loader, Field field) throws IllegalAccessException {
        Map<ConverterKeyBuild.ConverterKey, Converter> allConverter = MapUtils.newHashMapWithExpectedSize(41);
        putAllConverter(allConverter, new BigDecimalBooleanConverter());
        putAllConverter(allConverter, new BigDecimalNumberConverter());
        putAllConverter(allConverter, new BigDecimalStringConverter());
        putAllConverter(allConverter, new BigIntegerBooleanConverter());
        putAllConverter(allConverter, new BigIntegerNumberConverter());
        putAllConverter(allConverter, new BigIntegerStringConverter());
        putAllConverter(allConverter, new BooleanBooleanConverter());
        putAllConverter(allConverter, new BooleanNumberConverter());
        putAllConverter(allConverter, new BooleanStringConverter());
        putAllConverter(allConverter, new ByteBooleanConverter());
        putAllConverter(allConverter, new ByteNumberConverter());
        putAllConverter(allConverter, new ByteStringConverter());
        putAllConverter(allConverter, new DateNumberConverter());
        putAllConverter(allConverter, new DateStringConverter());
        putAllConverter(allConverter, new LocalDateNumberConverter());
        putAllConverter(allConverter, new LocalDateTimeStringConverter());
        putAllConverter(allConverter, new DoubleBooleanConverter());
        putAllConverter(allConverter, new DoubleNumberConverter());
        putAllConverter(allConverter, new DoubleStringConverter());
        putAllConverter(allConverter, new FloatBooleanConverter());
        putAllConverter(allConverter, new FloatNumberConverter());
        putAllConverter(allConverter, new FloatStringConverter());
        putAllConverter(allConverter, new IntegerBooleanConverter());
        putAllConverter(allConverter, new IntegerNumberConverter());
        putAllConverter(allConverter, new IntegerStringConverter());
        putAllConverter(allConverter, new LongBooleanConverter());
        putAllConverter(allConverter, new LongNumberConverter());
        putAllConverter(allConverter, new LongStringConverter());
        putAllConverter(allConverter, new ShortBooleanConverter());
        putAllConverter(allConverter, new ShortNumberConverter());
        putAllConverter(allConverter, new ShortStringConverter());
        putAllConverter(allConverter, new StringBooleanConverter());
        putAllConverter(allConverter, new StringNumberConverter());
        putAllConverter(allConverter, new StringStringConverter());
        putAllConverter(allConverter, new StringErrorConverter());
        putAllConverter(allConverter, new BigIntegerStringConverter());
        putAllConverter(allConverter, new CustomStringConverter());
        field.set(loader, allConverter);
    }

    private void initWriteConverter(DefaultConverterLoader loader, Field field) throws IllegalAccessException {
        Map<ConverterKeyBuild.ConverterKey, Converter> writeConverter = MapUtils.newHashMapWithExpectedSize(41);
        putWriteConverter(writeConverter, new BigDecimalNumberConverter());
        putWriteConverter(writeConverter, new BigIntegerNumberConverter());
        putWriteConverter(writeConverter, new BooleanBooleanConverter());
        putWriteConverter(writeConverter, new ByteNumberConverter());
        putWriteConverter(writeConverter, new DateDateConverter());
        putWriteConverter(writeConverter, new LocalDateTimeDateConverter());
        putWriteConverter(writeConverter, new DoubleNumberConverter());
        putWriteConverter(writeConverter, new FloatNumberConverter());
        putWriteConverter(writeConverter, new IntegerNumberConverter());
        putWriteConverter(writeConverter, new LongNumberConverter());
        putWriteConverter(writeConverter, new ShortNumberConverter());
        putWriteConverter(writeConverter, new StringStringConverter());
        putWriteConverter(writeConverter, new FileImageConverter());
        putWriteConverter(writeConverter, new InputStreamImageConverter());
        putWriteConverter(writeConverter, new ByteArrayImageConverter());
        putWriteConverter(writeConverter, new BoxingByteArrayImageConverter());
        putWriteConverter(writeConverter, new UrlImageConverter());
        putAllConverter(writeConverter, new BigDecimalStringConverter());
        putAllConverter(writeConverter, new BigIntegerStringConverter());
        putAllConverter(writeConverter, new BooleanStringConverter());
        putAllConverter(writeConverter, new ByteStringConverter());
        putAllConverter(writeConverter, new DateStringConverter());
        putAllConverter(writeConverter, new LocalDateTimeStringConverter());
        putAllConverter(writeConverter, new DoubleStringConverter());
        putAllConverter(writeConverter, new FloatStringConverter());
        putAllConverter(writeConverter, new IntegerStringConverter());
        putAllConverter(writeConverter, new LongStringConverter());
        putAllConverter(writeConverter, new ShortStringConverter());
        putAllConverter(writeConverter, new StringStringConverter());
        putAllConverter(writeConverter, new BigIntegerStringConverter());
        putAllConverter(writeConverter, new CustomStringConverter());
        field.set(loader, writeConverter);
    }

    private void putAllConverter(Map<ConverterKeyBuild.ConverterKey, Converter> convertMap, Converter converter) {
        convertMap.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);
    }

    private void putWriteConverter(Map<ConverterKeyBuild.ConverterKey, Converter> convertMap, Converter converter) {
        convertMap.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
    }
}
